Exploring x86 Assembly Language [WIP]
Introduction
Welcome to my personal journey as I delve into the intricacies of x86 assembly language. This series of notes have emerged from my spare-time learnings, guided by the illuminating teachings of David Wybiral on YouTube, all while juggling with my Software Engineering degree at Aalborg University. My intention is to foster a deeper comprehension of assembly language concepts, while also creating a useful reference for future coding endeavors.
Reference Guide
Dive into x86 assembly language yourself by following the series I've been using: Intro to x86 Assembly Language
x86 Assembly Language: A Brief Overview
The x86 assembly language is a form of low-level programming, designed for the original Intel 8086 microprocessor and its successive iterations. Despite the transition of modern processors to the x64 architecture, x86 assembly knowledge remains crucial for tasks such as reverse engineering and maintaining legacy code. This section encompasses my personal learnings and observations about the x86 assembly language.
Intro to x86 Assembly Language (Part 1)
Assembly isn't strictly a language but a human-friendly rendition of Machine Language, which provides machines with instruction sets to execute tasks.
- Assembly offers intricate control over the CPU, but this comes with challenges:
- It demands a robust understanding of diverse instructions and their synergistic functionalities.
- It necessitates verbose code for task execution.
- It misses the high-level abstractions found in other programming languages.
- The instruction set for ARM processor code differs from that used for Intel processors.
- Dissecting processor function:
- A processor follows a sequence of instructions to perform tasks.
- Registers
- Registers are the processor's working memory, housing values used for computations. They are transient storage spaces - data gets loaded, computations happen, and results are transferred to more permanent storage.
- The x86 architecture contains a mix of general and special purpose registers.
- Register size corresponds to the CPU architecture; 32-bit machines have 32-bit registers, and 64-bit machines have 64-bit registers.
- Backward compatibility is preserved by accessing subsets of registers; for instance, 32-bit code can execute on 64-bit machines by treating half of the 64-bit register as a 32-bit counterpart.
- The stack, akin to a "last in first out" (LIFO) structure, lets us push values for storage and pop them for retrieval. It's like a pile of books: pushing adds a book on top, while popping removes the top book.
- The stack functions as a memory array. Pushing and popping involve shifting an index or a pointer, which designates the stack's top. When pushing, the pointer moves and writes the new value to the new location. Pushing another value moves the pointer once more. Popping reads from the current location and moves the pointer backwards.
Assemblers convert assembly code into machine code, enabling machines to understand the instructions written in assembly language.